package com.zhoukai.business.util.license;

import cn.hutool.core.codec.Base64;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;

@Slf4j
public class EncryptUtil {

    private final static String RSA = "RSA";

    // 最大解密字节数，超出最大字节数需要分组加密
    private final static int MAX_ENCRYPT_BLOCK = 128;

    /**
     * 解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @return byte[] 解密数据
     */
    public static String decrypt(String data, String key) throws Exception {
        PrivateKey privateKey = loadKeyFromString(key);
        return decryptByAsymmetric(data, privateKey);
    }

    /**
     * 从字符串中加载私钥
     *
     * @param keyString : 私钥对字符串
     * @return : 私钥
     * @throws Exception
     */
    public static PrivateKey loadKeyFromString(String keyString) throws Exception {

        // 进行Base64解码
        byte[] decode = Base64.decode(keyString);
        // 获取密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        // 构建密钥规范
        PKCS8EncodedKeySpec key = new PKCS8EncodedKeySpec(decode);
        // 生成私钥
        return keyFactory.generatePrivate(key);

    }

    /**
     * 非对称解密数据
     *
     * @param encrypted : 密文
     * @param key       : 密钥
     * @return : 原文
     * @throws Exception
     */
    public static String decryptByAsymmetric(String encrypted, Key key) throws Exception {
        // 获取Cipher对象
        Cipher cipher = Cipher.getInstance(RSA);
        // 初始化模式(解密)和密钥
        cipher.init(Cipher.DECRYPT_MODE, key);
        return new String(getMaxResultDecrypt(encrypted, cipher));

    }

    /**
     * 分段处理解密数据
     *
     * @param decryptText : 加密文本
     * @param cipher      : Cipher对象
     * @throws Exception
     */
    private static byte[] getMaxResultDecrypt(String decryptText, Cipher cipher) throws Exception {
        byte[] inputArray = Base64.decode(decryptText.getBytes(StandardCharsets.UTF_8));
        int inputLength = inputArray.length;
        // 标识
        int offSet = 0;
        byte[] resultBytes = {};
        byte[] cache = {};
        while (inputLength - offSet > 0) {
            if (inputLength - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(inputArray, offSet, MAX_ENCRYPT_BLOCK);
                offSet += MAX_ENCRYPT_BLOCK;
            } else {
                cache = cipher.doFinal(inputArray, offSet, inputLength - offSet);
                offSet = inputLength;
            }
            resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
            System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
        }
        return resultBytes;
    }

}

